package ai.fabu.dataplatform.service.GRPCServer;

import ai.fabu.dataplatform.*;
import ai.fabu.dataplatform.bean.bagdata.BagData;
import ai.fabu.dataplatform.bean.framedata.FrameData;
import ai.fabu.dataplatform.bean.groupdata.GroupData;
import ai.fabu.dataplatform.bean.metadata.GetMetadata;
import ai.fabu.dataplatform.bean.topicdata.TopicData;
import ai.fabu.dataplatform.bean.util.IndexData;
import ai.fabu.dataplatform.bean.util.Pair;
import ai.fabu.dataplatform.constant.ResultCode;
import ai.fabu.dataplatform.help.Result;
import ai.fabu.dataplatform.service.ApiForImportBagService;
import ai.fabu.dataplatform.service.ApiService;
import com.google.protobuf.ByteString;
import com.google.protobuf.ProtocolStringList;
import com.mongodb.MongoException;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.springboot.autoconfigure.grpc.server.GrpcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.UncategorizedMongoDbException;

import java.util.ArrayList;
import java.util.List;

import static ai.fabu.dataplatform.constant.ConstantValue.*;

@Slf4j
public class DataPlatFormMetadataServer {
    @GrpcService(MetadataServiceGrpc.class)
    private static class DataPlatformMetadataImpl extends MetadataServiceGrpc.MetadataServiceImplBase{
        @Autowired
        ApiService apiService;
        @Autowired
        ApiForImportBagService apiForImportBagService;






        // save

        private void saveMetadata(SaveMetadataRequest request, StreamObserver<SaveResponse> responseObserver, Class<?> T, int type){
            Index index = request.getIndex();
            List<Metadata> metadatasList = request.getMetadatasList();
            List<Pair<String, byte[]>> metadataList = new ArrayList<>();
            metadatasList.forEach(metadata -> metadataList.add(new Pair<>(metadata.getKey(), metadata.getValue().toByteArray())));
            IndexData indexData = new IndexData(index.getGroupName(), index.getBagName(), index.getTopicName(), index.getFrameNo());
            Result<Long> result;
                try{
                    result = apiService.saveMetadata(indexData, T, type, metadataList);
                } catch (Exception e){
                    FunctionUtil.errorHandler(responseObserver, "saveMetadata", ResultCode.SYSTEM_ERROR.getMsg());
                    throw e;
                }

            if(result.getCode() == ResultCode.SUCCESS.getCode()){
                SaveResponse response = SaveResponse.newBuilder().setUpdateNum(result.getData()).build();
                responseObserver.onNext(response);
                responseObserver.onCompleted();
            }
            else
                FunctionUtil.errorHandler(result, responseObserver, "saveMetadata");
        }

        @Override
        public void saveGroupMetadata(SaveMetadataRequest request, StreamObserver<SaveResponse> responseObserver) {
            saveMetadata(request, responseObserver, GroupData.class, GROUP_TYPE);
        }

        @Override
        public void saveBagMetadata(SaveMetadataRequest request, StreamObserver<SaveResponse> responseObserver) {
            saveMetadata(request, responseObserver, BagData.class, BAG_TYPE);
        }

        @Override
        public void saveTopicMetadata(SaveMetadataRequest request, StreamObserver<SaveResponse> responseObserver) {
            saveMetadata(request, responseObserver, TopicData.class, TOPIC_TYPE);
        }

        @Override
        public void saveFrameMetadata(SaveMetadataRequest request, StreamObserver<SaveResponse> responseObserver) {
            saveMetadata(request, responseObserver, FrameData.class, FRAME_TYPE);
        }

        // 多个文件多个frame 进行存储
        @Override
        public void saveFramesMetadata(SaveMetadataRequest request, StreamObserver<SaveResponse> responseObserver) {
            Index index = request.getIndex();
            IndexData indexData = new IndexData(index.getGroupName(), index.getBagName(), index.getTopicName(), index.getFrameNo());
            List<Metadata> metadatasList = request.getMetadatasList();
            List<Pair<String, byte[]>> metadataList = new ArrayList<>();
            metadatasList.forEach(metadata -> metadataList.add(new Pair<>(metadata.getKey(), metadata.getValue().toByteArray())));
            Result<Long> result = new Result<>();
            try{
                result = apiForImportBagService.saveFramesMetadata(indexData, metadataList);
            } catch (Exception e){
                FunctionUtil.errorHandler(responseObserver, "saveFramesMetadata", ResultCode.SYSTEM_ERROR.getMsg());
                throw e;
            }

            if (result.getCode() == ResultCode.SUCCESS.getCode()){
                SaveResponse response = SaveResponse.newBuilder().setUpdateNum(result.getData()).build();
                responseObserver.onNext(response);
                responseObserver.onCompleted();
            }
            else
                FunctionUtil.errorHandler(result, responseObserver, "saveFramesMetadata");
        }



        // get

        private void getMetadata(GetMetadataRequest request, StreamObserver<GetMetadataResponse> responseObserver, int type){
            Index index = request.getIndex();
            ProtocolStringList protocolStringList = request.getKeyList();
            List<String> keyList = new ArrayList<>(protocolStringList);
            IndexData indexData = new IndexData(index.getGroupName(), index.getBagName(), index.getTopicName(), index.getFrameNo());
            Result<List<GetMetadata>> result;
            try{
                result = apiService.getMetadata(indexData, type, keyList);
            }
            catch (Exception e){
                FunctionUtil.errorHandler(responseObserver, "getMetadata", ResultCode.SYSTEM_ERROR.getMsg());
                throw e;
            }

            if(result.getCode() == ResultCode.SUCCESS.getCode()){
                List<GetMetadata> resultData = result.getData();
                for (GetMetadata metadata : resultData) {
                    indexData = metadata.getIndexData();
                    index = Index.newBuilder().setGroupName(indexData.getGroupName()).setBagName(indexData.getBagName()).setTopicName(indexData.getTopicName()).setFrameNo(indexData.getFrameNo()).build();
                    List<Pair<String, byte[]>> pairList = metadata.getData();
                    GetMetadataResponse.Builder builder = GetMetadataResponse.newBuilder().setIndex(index);
                    pairList.forEach(pair -> builder.addMetadatas(Metadata.newBuilder().setKey(pair.getKey()).setValue(ByteString.copyFrom(pair.getValue()))));
                    responseObserver.onNext(builder.build());
                }
                responseObserver.onCompleted();
            }
            else
                FunctionUtil.errorHandler(result, responseObserver, "getMetadata");
        }

        @Override
        public void getGroupMetadata(GetMetadataRequest request, StreamObserver<GetMetadataResponse> responseObserver) {
            getMetadata(request, responseObserver, GROUP_TYPE);
        }

        @Override
        public void getBagMetadata(GetMetadataRequest request, StreamObserver<GetMetadataResponse> responseObserver) {
            getMetadata(request, responseObserver, BAG_TYPE);
        }

        @Override
        public void getTopicMetadata(GetMetadataRequest request, StreamObserver<GetMetadataResponse> responseObserver) {
            getMetadata(request, responseObserver, TOPIC_TYPE);
        }

        @Override
        public void getFrameMetadata(GetMetadataRequest request, StreamObserver<GetMetadataResponse> responseObserver) {
            getMetadata(request, responseObserver, FRAME_TYPE);
        }
    }
}
